讓我們把焦點從流程的部分轉回應用程式上,現在第二頁面還缺少一個下一步的按鈕,同時得做一些邏輯驗證,首先在版面上新增一個按鈕及程式上加入點擊的監聽,這些相信難不倒已經學習過之前章節的讀者。
接著使用 arrayListOf 盛裝,自三個 switch (北極、南極、芬蘭) 讀取的選擇狀態,到這邊可以先試試看使用 println(answer) 查看內容物,接著再使用 lambda 設計我們需要的邏輯:三個至少要選一個。

這裡使用 any 去判斷集合中是否有任何 true 值,Line: 28 的寫法是 Line: 29 的簡化版,在先前的 Day 11 有相關說明,各位應該可以感覺到,簡化前後以第一直覺去看該行程式碼,哪一段比較能快速理解邏輯條件;又哪一段撰寫起來較迅速簡潔。但是 IDE 會提示你簡化,受不了那條線一直出現在那邊的人應該不少...,採用簡化版本再搭配註解也是個不錯的辦法。
以下是上圖程式執行成果,在沒選擇的狀況下點按鈕後印出的結果,讀者也可以試試看任選項目後會有什麼不同:
I/System.out: [false, false, false]
false
false
接著把第三頁面加入應用程式中,並且完成邏輯判斷式,可以利用 Toast.makeText() 方法,顯示訊息到螢幕上呈現,第一個參數傳入目前頁面,使用關鍵字 this 即可,第二參數放入想要顯示的文字,如同先前課程提到的,應該採用文字資源管理的方式實作,在這邊的示範為了方便就直接放入文字,第三參數可決定訊息顯示持續的時間,有 Toast.LENGTH_SHORT、Toast.LENGTH_LONG 兩種可以選擇,分別是 2 秒與 3.5 秒的差別。

執行結果如下:

接著會有一個問題:第三頁面要怎麼知道在第二頁面的選項呢?我們必須設計一個機制將第二頁的值傳送過去,使用 xxx.putExtra() 方法,其中 xxx 是目標頁面,putExtra 可以放入許多型態的資料,這邊我們先用純文字示範。

putExtra() 第一個參數要指定一個 ID,做為取值時的識別,在這邊使用常數的定義方式,讓我們先命名 (規則:全部大寫,以 EXTRA_ 開頭,後面根據常數用途決定)。

暫時是紅字沒關係,接著到專案總管上新增一個新的 Kotlin File/Class。

新增的檔案命名為:ExtraConstants,用來存放所有的 ID,方便管理。

在新檔案中加入常數字串變數,字串內容也是依據用途決定,只要不重複即可。

此時回到第二頁面就能看到紅字錯誤提示已經消失,接著切換到第三頁面,使用 intent.getStringExtra() 取得剛剛傳入的值,不同的形態會有不一樣的提取使用方法,接著用剛剛介紹過的 Toast 將內容顯示在螢幕上。

成功!正確無誤。

但我們的程式是一個 List 型態,要如何傳遞呢?首先必須將整個集合序列化 (Serializable) 轉成 Bundle() 的型態,再將此物件傳送。 Serializable 有其效能上的缺點,文章後段會說明
val extra = Bundle()
extra.putSerializable(EXTRA_AURORA_LIST, answerList)
thirdActivity.putExtra(EXTRA_AURORA_LIST, extra)
另一個頁面接收時,反向處理,先取出 Bundle 型態,再將之解序列化,並轉型回 ArrayList<Boolean> 格式,讀者可以試著使用 println 印出結果。
var auroraList = intent.getBundleExtra(EXTRA_AURORA_LIST).getSerializable(EXTRA_AURORA_LIST) as ArrayList<Boolean>
println(auroraList)
在 Run 視窗中,println 出來的值是:I/System.out: [false, true, false],這樣的格式有個缺點:不知道選項到底代表什麼,若要處理這個問題,可以將 arrayList 改為使用 hashMap,所有相關程式調整幅度不大,只有三個地方需要修改,請查看下列兩張截圖的紅框處。


修改後可以看到 println 的結果變成:I/System.out: {Arctic=false, Antarctic=true, Finland=true},對於後續使用上會比較方便。另外 Serializable 的效能表現其實是有問題的,可以參考這篇文章的比較。
圖片來源:https://android.jlelse.eu/parcelable-vs-serializable-6a2556d51538
在明天的章節會介紹改用 Parcelable方式,搭配使用之前提過的 data class 來進行資料傳遞的乘載。
額外討論:在所有教學中有用過三種按鈕設定監聽點擊的方法,各位覺得在實作上有什麼優缺點的不同?歡迎大家提出自己的看法,以及會選擇的是哪一個方式。
// 第一種:直接在 onCreate 完成
goBtn.setOnClickListener {
// Do something
}
// 第二種:透過 layout.xml 鏈結
fun backBtnOnClick(view: View) {
// Do something
}
// 第三種:在 onCreate 設定一行監聽,呼叫另外獨立的方法
nextBtn.setOnClickListener{ nextBtnOnClick() }
fun nextBtnOnClick() {
// Do something
}
那麼今天的教學就到這邊,我們明天見!
資料參考
Toast length long and short 差異
https://stackoverflow.com/questions/7965135/what-is-the-duration-of-a-toast-length-long-and-length-shortIntent putExtra 用於集合
https://stackoverflow.com/questions/18050030/intent-putextra-arraylistnamevaluepairParcelable vs Serializable
https://android.jlelse.eu/parcelable-vs-serializable-6a2556d51538Activity-Android Developers (中文)
https://developer.android.com/guide/components/activities?hl=zh-twKotlin for Android: Beginner to Advanced | Udemy
https://www.udemy.com/devslopes-android-kotlin/